<!--
  Copyright JS Foundation and other contributors, http://js.foundation
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at
  http://www.apache.org/licenses/LICENSE-2.0
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->
<style>

    .mqtt-form-row-cols2 > input.mqtt-form-row-col1 {
        width: calc(35% - 75px);
    }
    .mqtt-form-row-cols2 > select.mqtt-form-row-col1 {
        width: calc(35% - 75px);
    }

    .mqtt-form-row-cols2 > label.mqtt-form-row-col2 {
        width: 100px;
        margin-left: 42px;
        display: inline-block;
    }
    .mqtt-form-row-cols2 > input.mqtt-form-row-col2 {
        width: calc(35% - 75px);
        display: inline-block;
    }
    .mqtt-form-row-cols2 > select.mqtt-form-row-col2 {
        width: calc(35% - 75px);
        display: inline-block;
    }
    .form-row.mqtt5-out > label {
        width: 130px;
    }
    .form-row.mqtt-flags-row > label {
        vertical-align: top;
    }
    .form-row.mqtt-flags-row > .mqtt-flags {
        display: inline-block;
        width: 70%
    }

    .form-row.mqtt-flags-row > .mqtt-flags > .mqtt-flag > label {
        display: block;
        width: 100%;
    }
    .form-row.mqtt-flags-row > .mqtt-flags > .mqtt-flag > label > input {
        position: relative;
        vertical-align: bottom;
        top: -2px;
        width: 15px;
        height: 15px;
    }
    .form-row-mqtt5 {
        display: none;
    }
    .form-row-mqtt5.form-row-mqtt5-active:not(.form-row-mqtt-static-disabled) {
        display: block
    }
    .form-row-mqtt-static-disabled {
        display: none;
        /* opacity: 0.3;
        pointer-events: none; */
    }
    .form-row.form-row-mqtt-datatype-tip > .form-tips {
        width: calc(70% - 18px);
        display: inline-block;
        margin-top: -8px;
    }

</style>

<script type="text/html" data-template-name="mqtt in">
    <div class="form-row">
        <label for="node-input-broker"><i class="fa fa-globe"></i> <span data-i18n="mqtt.label.broker"></span></label>
        <input type="text" id="node-input-broker">
    </div>
    <div class="form-row">
        <label for="node-input-topicType" data-i18n="mqtt.label.action"></label>
        <select id="node-input-topicType" style="width: 70%">
            <option value="topic" data-i18n="mqtt.label.staticTopic"></option>
            <option value="dynamic" data-i18n="mqtt.label.dynamicTopic"></option>
        </select>
        <input type="hidden" id="node-input-inputs">
    </div>
    <div class="form-row form-row-mqtt-static">
        <label for="node-input-topic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
        <input type="text" id="node-input-topic" data-i18n="[placeholder]common.label.topic">
    </div>
    <div class="form-row form-row-mqtt-static">
        <label for="node-input-qos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
        <select id="node-input-qos" style="width:125px !important">
            <option value="0">0</option>
            <option value="1">1</option>
            <option value="2">2</option>
        </select>
    </div>
    <div class="form-row mqtt-flags-row form-row-mqtt5 form-row-mqtt-static">
        <label for="node-input-nl" ><i class="fa fa-flag"></i> <span data-i18n="mqtt.label.flags">Flags</span></label>
        <div class="mqtt-flags">
            <div class="mqtt-flag">
                <label for="node-input-nl">
                    <input type="checkbox" id="node-input-nl">
                    <span data-i18n="mqtt.label.nl"></span>
                </label>
            </div>
            <div class="mqtt-flag">
                <label for="node-input-rap">
                    <input type="checkbox" id="node-input-rap">
                    <span data-i18n="mqtt.label.rap"></span>
                </label>
            </div>
        </div>
    </div>
    <div class="form-row form-row-mqtt5 form-row-mqtt-static">
        <label for="node-input-rh" style="width:100%"><i class="fa fa-tag"></i> <span data-i18n="mqtt.label.rh"></span></label>
        <select id="node-input-rh" style="margin-left: 104px; width: 70%">
            <option value="0" data-i18n="mqtt.label.rh0"></option>
            <option value="1" data-i18n="mqtt.label.rh1"></option>
            <option value="2" data-i18n="mqtt.label.rh2"></option>
        </select>
    </div>
    <div class="form-row">
        <label for="node-input-datatype"><i class="fa fa-sign-out"></i> <span data-i18n="mqtt.label.output"></span></label>
        <select id="node-input-datatype" style="width:70%;">
            <option value="auto-detect" data-i18n="mqtt.output.auto-detect"></option>
            <option value="auto" data-i18n="mqtt.output.auto"></option>
            <option value="buffer" data-i18n="mqtt.output.buffer"></option>
            <option value="utf8" data-i18n="mqtt.output.string"></option>
            <option value="json" data-i18n="mqtt.output.json"></option>
            <option value="base64" data-i18n="mqtt.output.base64"></option>
        </select>
    </div>
    <div class="form-row form-row-mqtt-datatype-tip">
        <label> &nbsp; </label>
        <div class="form-tips" id="mqtt-in-datatype-depreciated-tip"><span data-i18n="mqtt.label.auto-mode-depreciated"></span></div>
    </div>
    <div class="form-row">
        <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
        <input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
    </div>
</script>

<script type="text/html" data-template-name="mqtt out">
    <div class="form-row">
        <label for="node-input-broker"><i class="fa fa-globe"></i> <span data-i18n="mqtt.label.broker"></span></label>
        <input type="text" id="node-input-broker">
    </div>
    <div class="form-row">
        <label for="node-input-topic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
        <input type="text" id="node-input-topic" data-i18n="[placeholder]common.label.topic">
    </div>

    <div class="form-row mqtt-form-row-cols2">
        <label for="node-input-qos" class="mqtt-form-row-col1"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
        <select id="node-input-qos" class="mqtt-form-row-col1">
            <option value=""></option>
            <option value="0">0</option>
            <option value="1">1</option>
            <option value="2">2</option>
        </select>

        <label for="node-input-retain" class="mqtt-form-row-col2"><i class="fa fa-history"></i> <span data-i18n="mqtt.retain"></span></label>
        <select id="node-input-retain" class="mqtt-form-row-col2" >
            <option value=""></option>
            <option value="false" data-i18n="mqtt.false"></option>
            <option value="true" data-i18n="mqtt.true"></option>
        </select>
    </div>
    <div class="form-row mqtt5 mqtt5-out">
        <label for="node-input-userProps"><span data-i18n="mqtt.label.userProperties"></span></label>
        <input type="text" id="node-input-userProps" style="width: calc(100% - 166px);">
    </div>
    <div class="form-row mqtt5 mqtt5-out">
        <label for="node-input-respTopic"><span data-i18n="mqtt.label.responseTopic"></span></label>
        <input type="text" id="node-input-respTopic" style="width: calc(100% - 166px);">
    </div>
    <div class="form-row mqtt5 mqtt5-out">
        <label for="node-input-correl"><span data-i18n="mqtt.label.correlationData"></span></label>
        <input type="text" id="node-input-correl" style="width: calc(100% - 166px);">
    </div>
    <div class="form-row mqtt5 mqtt5-out">
        <label for="node-input-contentType"><span data-i18n="mqtt.label.contentType"></span></label>
        <input type="text" id="node-input-contentType" style="width: calc(100% - 166px);">
    </div>

    <div class="form-row mqtt-form-row-cols2 mqtt5 mqtt5-out">
        <label for="node-input-expiry" class="mqtt-form-row-col1"><span data-i18n="mqtt.label.expiry"></span></label>
        <input id="node-input-expiry"  style="width: calc(100% - 166px);" class="mqtt-form-row-col1" >
    </div>

    <div class="form-row">
        <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
        <input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name">
    </div>
    <div class="form-tips"><span data-i18n="mqtt.tip"></span></div>
</script>

<script type="text/html" data-template-name="mqtt-broker">
    <div class="form-row">
        <label for="node-config-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
        <input type="text" id="node-config-input-name" data-i18n="[placeholder]common.label.name">
    </div>
    <div class="form-row">
        <ul style="min-width: 600px; margin-bottom: 20px;" id="node-config-mqtt-broker-tabs"></ul>
    </div>
    <div id="node-config-mqtt-broker-tabs-content" style="min-height:150px;">
        <div id="mqtt-broker-tab-connection" style="display:none">
            <div class="form-row node-input-broker">
                <label for="node-config-input-broker"><i class="fa fa-globe"></i> <span data-i18n="mqtt.label.broker"></span></label>
                <input type="text" id="node-config-input-broker" style="width: calc(100% - 300px);" data-i18n="[placeholder]mqtt.label.example">
                <label for="node-config-input-port" style="margin-left:20px; width:43px; "> <span data-i18n="mqtt.label.port"></span></label>
                <input type="text" id="node-config-input-port" data-i18n="[placeholder]mqtt.label.port" style="width:55px">
            </div>
            <div class="form-row" style="margin-bottom:0">
                <input type="checkbox" id="node-config-input-autoConnect" style="margin: 0 5px 0 104px; display: inline-block; width: auto;">
                <label for="node-config-input-autoConnect" style="width: auto"><span data-i18n="mqtt.label.auto-connect"></span></label>
            </div>
            <div class="form-row" style="height: 34px;">
                <input type="checkbox" id="node-config-input-usetls" style="height: 34px; margin: 0 5px 0 104px; display: inline-block; width: auto; vertical-align: top;">
                <label for="node-config-input-usetls" style="width: 100px; line-height: 34px;"><span data-i18n="mqtt.label.use-tls"></span></label>
                <span id="node-config-row-tls" class="hide"><input style="width: 320px;" type="text" id="node-config-input-tls"></span>
            </div>
            <div class="form-row">
                <label for="node-config-input-protocolVersion"><i class="fa fa-cog"></i> <span data-i18n="mqtt.label.protocolVersion"></span></label>
                <select id="node-config-input-protocolVersion" style="width:70%;">
                    <option value="3" data-i18n="mqtt.label.protocolVersion3"></option>
                    <option value="4" data-i18n="mqtt.label.protocolVersion4"></option>
                    <option value="5" data-i18n="mqtt.label.protocolVersion5"></option>
                </select>
            </div>
            <div class="form-row">
                <label for="node-config-input-clientid"><i class="fa fa-tag"></i> <span data-i18n="mqtt.label.clientid"></span></label>
                <input type="text" id="node-config-input-clientid" data-i18n="[placeholder]mqtt.placeholder.clientid">
            </div>
            <div class="form-row">
                <label for="node-config-input-keepalive"><i class="fa fa-heartbeat"></i> <span data-i18n="mqtt.label.keepalive"></span></label>
                <input type="number" min="0" id="node-config-input-keepalive" style="width: 100px">
            </div>
            <div class="form-row" style="margin-bottom:0">
                <label style="vertical-align:top;"><i class="fa fa-info"></i> <span data-i18n="mqtt.label.session"></span></label>
                <div style="display: inline-block; width:calc(100% - 110px)">
                    <div class="form-row">
                        <label for="node-config-input-cleansession" style="width: auto;">
                            <input type="checkbox" id="node-config-input-cleansession" style="position: relative;vertical-align: bottom; top: -2px; width: 15px;height: 15px;">
                            <span id="node-config-input-cleansession-label" data-i18n="mqtt.label.cleansession"></span>
                        </label>
                    </div>
                    <div class="form-row mqtt-persistence">
                        <label for="node-config-input-autoUnsubscribe" style="width: auto;">
                            <input type="checkbox" id="node-config-input-autoUnsubscribe" style="position: relative;vertical-align: bottom; top: -2px; width: 15px;height: 15px;">
                            <span id="node-config-input-autoUnsubscribe-label" data-i18n="mqtt.label.autoUnsubscribe"></span>
                        </label>
                    </div>
                    <div class="form-row mqtt5">
                        <label style="width:auto" for="node-config-input-sessionExpiry"><span data-i18n="mqtt.label.sessionExpiry"></span></label>
                        <input type="number" min="0" id="node-config-input-sessionExpiry" style="width: 100px" >
                    </div>
                </div>
            </div>
            <div class="form-row mqtt5">
                <label style="width: 125px;" for="node-config-input-userProps"><span data-i18n="mqtt.label.userProperties"></span></label>
                <input type="text" id="node-config-input-userProps" style="width: calc(100% - 166px);">
            </div>
            <br>
        </div>
        <div id="mqtt-broker-tab-security" style="display:none">
            <div class="form-row">
                <label for="node-config-input-user"><i class="fa fa-user"></i> <span data-i18n="common.label.username"></span></label>
                <input type="text" id="node-config-input-user">
            </div>
            <div class="form-row">
                <label for="node-config-input-password"><i class="fa fa-lock"></i> <span data-i18n="common.label.password"></span></label>
                <input type="password" id="node-config-input-password">
            </div>
        </div>
        <div id="mqtt-broker-tab-messages" style="display:none">
            <div id="mqtt-broker-section-birth">
                <div class="red-ui-palette-header">
                    <i class="fa fa-angle-down"></i><span data-i18n="mqtt.sections-label.birth-message"></span>
                </div>
                <div class="section-content" style="padding:10px 0 0 10px">
                    <div class="form-row">
                        <label style="width: 100px !important;" for="node-config-input-birthTopic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
                        <input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-birthTopic" data-i18n="[placeholder]mqtt.placeholder.birth-topic">
                        <label style="margin-left: 10px; width: 90px !important;" for="node-config-input-birthRetain"><i class="fa fa-history"></i> <span data-i18n="mqtt.label.retain"></span></label>
                        <select id="node-config-input-birthRetain" style="width:75px !important">
                            <option value="false" data-i18n="mqtt.false"></option>
                            <option value="true" data-i18n="mqtt.true"></option>
                        </select>
                    </div>
                    <div class="form-row">
                        <label style="width: 100px !important;" for="node-config-input-birthPayload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
                        <input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-birthPayload" style="width:300px" data-i18n="[placeholder]common.label.payload">
                        <label style="margin-left: 10px; width: 90px !important;" for="node-config-input-birthQos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
                        <select id="node-config-input-birthQos" style="width:75px !important">
                            <option value="0">0</option>
                            <option value="1">1</option>
                            <option value="2">2</option>
                        </select>
                    </div>
                    <div class="form-row mqtt5 mqtt5-out">
                        <label for="node-config-input-birth-contentType" data-i18n="mqtt.label.contentType"></label>
                        <input type="text" style="width:calc(100% - 200px);" id="node-config-input-birth-contentType">
                    </div>
                    <div class="form-row mqtt5 mqtt5-out">
                        <label for="node-config-input-birth-props" data-i18n="mqtt.label.userProperties"></label>
                        <input type="text" style="width:calc(100% - 200px);" id="node-config-input-birth-props">
                    </div>
                    <div class="form-row mqtt5 mqtt5-out">
                        <label for="node-config-input-birth-respTopic"><span data-i18n="mqtt.label.responseTopic"></span></label>
                        <input type="text" id="node-config-input-birth-respTopic" style="width: calc(100% - 200px);">
                    </div>
                    <div class="form-row mqtt5 mqtt5-out">
                        <label for="node-config-input-birth-correl"><span data-i18n="mqtt.label.correlationData"></span></label>
                        <input type="text" id="node-config-input-birth-correl" style="width: calc(100% - 200px);">
                    </div>
                    <div class="form-row mqtt5 mqtt5-out">
                        <label for="node-config-input-birth-expiry"><span data-i18n="mqtt.label.expiry"></span></label>
                        <input id="node-config-input-birth-expiry"  style="width: calc(100% - 200px);">
                    </div>
                </div>
            </div>
            <div id="mqtt-broker-section-close">
                <div class="red-ui-palette-header">
                    <i class="fa fa-angle-down"></i><span data-i18n="mqtt.sections-label.close-message"></span>
                </div>
                <div class="section-content" style="padding:10px 0 0 10px">
                    <div class="form-row">
                        <label style="width: 100px !important;" for="node-config-input-closeTopic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
                        <input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-closeTopic" style="width:300px" data-i18n="[placeholder]mqtt.placeholder.close-topic">
                        <label style="margin-left: 10px; width: 90px !important;" for="node-config-input-closeRetain"><i class="fa fa-history"></i> <span data-i18n="mqtt.label.retain"></span></label>
                        <select id="node-config-input-closeRetain" style="width:75px !important">
                            <option value="false" data-i18n="mqtt.false"></option>
                            <option value="true" data-i18n="mqtt.true"></option>
                        </select>
                    </div>
                    <div class="form-row">
                        <label style="width: 100px !important;" for="node-config-input-closePayload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
                        <input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-closePayload" style="width:300px" data-i18n="[placeholder]common.label.payload">
                        <label style="margin-left: 10px; width: 90px !important;" for="node-config-input-closeQos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
                        <select id="node-config-input-closeQos" style="width:75px !important">
                            <option value="0">0</option>
                            <option value="1">1</option>
                            <option value="2">2</option>
                        </select>
                    </div>
                    <div class="form-row mqtt5 mqtt5-out">
                        <label for="node-config-input-close-contentType" data-i18n="mqtt.label.contentType"></label>
                        <input type="text" style="width:calc(100% - 200px);" id="node-config-input-close-contentType">
                    </div>
                    <div class="form-row mqtt5 mqtt5-out">
                        <label for="node-config-input-close-props" data-i18n="mqtt.label.userProperties"></label>
                        <input type="text" style="width:calc(100% - 200px);" id="node-config-input-close-props">
                    </div>
                    <div class="form-row mqtt5 mqtt5-out">
                        <label for="node-config-input-close-respTopic"><span data-i18n="mqtt.label.responseTopic"></span></label>
                        <input type="text" id="node-config-input-close-respTopic" style="width: calc(100% - 200px);">
                    </div>
                    <div class="form-row mqtt5 mqtt5-out">
                        <label for="node-config-input-close-correl"><span data-i18n="mqtt.label.correlationData"></span></label>
                        <input type="text" id="node-config-input-close-correl" style="width: calc(100% - 200px);">
                    </div>
                    <div class="form-row mqtt5 mqtt5-out">
                        <label for="node-config-input-close-expiry"><span data-i18n="mqtt.label.expiry"></span></label>
                        <input id="node-config-input-close-expiry"  style="width: calc(100% - 200px);">
                    </div>
                </div>
            </div>
            <div id="mqtt-broker-section-will">
                <div class="red-ui-palette-header">
                    <i class="fa fa-angle-down"></i><span data-i18n="mqtt.sections-label.will-message"></span>
                </div>
                <div class="section-content" style="padding:10px 0 0 10px">
                    <div class="form-row">
                        <label style="width: 100px !important;" for="node-config-input-willTopic"><i class="fa fa-tasks"></i> <span data-i18n="common.label.topic"></span></label>
                        <input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-willTopic" style="width:300px" data-i18n="[placeholder]mqtt.placeholder.will-topic">
                        <label style="margin-left: 10px; width: 90px !important;" for="node-config-input-willRetain"><i class="fa fa-history"></i> <span data-i18n="mqtt.label.retain"></span></label>
                        <select id="node-config-input-willRetain" style="width:75px !important">
                            <option value="false" data-i18n="mqtt.false"></option>
                            <option value="true" data-i18n="mqtt.true"></option>
                        </select>
                    </div>
                    <div class="form-row">
                        <label style="width: 100px !important;" for="node-config-input-willPayload"><i class="fa fa-envelope"></i> <span data-i18n="common.label.payload"></span></label>
                        <input style="width: calc(100% - 300px) !important" type="text" id="node-config-input-willPayload" style="width:300px" data-i18n="[placeholder]common.label.payload">
                        <label style="margin-left: 10px; width: 90px !important;" for="node-config-input-willQos"><i class="fa fa-empire"></i> <span data-i18n="mqtt.label.qos"></span></label>
                        <select id="node-config-input-willQos" style="width:75px !important">
                            <option value="0">0</option>
                            <option value="1">1</option>
                            <option value="2">2</option>
                        </select>
                    </div>
                    <div class="form-row mqtt5">
                        <label><span data-i18n="mqtt.label.delay"></span></label>
                        <input type="number" min="0" id="node-config-input-will-delay" style="width: 100px" >
                    </div>
                    <div class="form-row mqtt5 mqtt5-out">
                        <label for="node-config-input-will-contentType" data-i18n="mqtt.label.contentType"></label>
                        <input type="text" style="width:calc(100% - 200px);" id="node-config-input-will-contentType">
                    </div>
                    <div class="form-row mqtt5 mqtt5-out">
                        <label for="node-config-input-will-props" data-i18n="mqtt.label.userProperties"></label>
                        <input type="text" style="width:calc(100% - 200px);" id="node-config-input-will-props">
                    </div>
                    <div class="form-row mqtt5 mqtt5-out">
                        <label for="node-config-input-will-respTopic"><span data-i18n="mqtt.label.responseTopic"></span></label>
                        <input type="text" id="node-config-input-will-respTopic" style="width: calc(100% - 200px);">
                    </div>
                    <div class="form-row mqtt5 mqtt5-out">
                        <label for="node-config-input-will-correl"><span data-i18n="mqtt.label.correlationData"></span></label>
                        <input type="text" id="node-config-input-will-correl" style="width: calc(100% - 200px);">
                    </div>
                    <div class="form-row mqtt5 mqtt5-out">
                        <label for="node-config-input-will-expiry"><span data-i18n="mqtt.label.expiry"></span></label>
                        <input id="node-config-input-will-expiry"  style="width: calc(100% - 200px);">
                    </div>
                </div>
            </div>
        </div>
    </div>
</script>

<script type="text/javascript">
(function() {

    var typedInputNoneOpt = {
        value: 'none',
        label: RED._("node-red:mqtt.label.none"),
        hasValue: false
    };
    var makeTypedInputOpt = function(value){
        return {
            value: value,
            label:value,
            hasValue: false
        }
    }
    var contentTypeOpts = [
        typedInputNoneOpt,
        makeTypedInputOpt("application/json"),
        makeTypedInputOpt("application/octet-stream"),
        makeTypedInputOpt("text/csv"),
        makeTypedInputOpt("text/html"),
        makeTypedInputOpt("text/plain"),
        {
            value: "other",
            label: RED._("node-red:mqtt.label.other"),
            icon: "red/images/typedInput/az.svg"
        }
    ];

    function getDefaultContentType(value) {
        var defaultContentType;
        var matchedContentType = contentTypeOpts.filter(function(v) {
            return v.value === value;
        })
        if (matchedContentType.length > 0) {
            defaultContentType = matchedContentType[0].value;
        }
        if (value && !defaultContentType) {
            defaultContentType = 'other';
        }
        return defaultContentType || 'none'
    }
    /**
     * Test a topic string is valid for publishing
     * @param {string} topic
     * @returns `true` if it is a valid topic
     */
    function validateMQTTPublishTopic(topic, opts) {
        if(!topic || topic == "" || !/[\+#\b\f\n\r\t\v\0]/.test(topic)) {
            return true;
        }
        return RED._("node-red:mqtt.errors.invalid-topic");
    }
    RED.nodes.registerType('mqtt-broker',{
        category: 'config',
        defaults: {
            name: {value:""},
            broker: {value:"",required:true},
            port: {
                value:1883,required:false,
                label: RED._("node-red:mqtt.label.port"),
                validate:RED.validators.number(true)},
            tls: {type:"tls-config",required: false,
                  label:RED._("node-red:mqtt.label.use-tls") },
            clientid: {value:"", validate: function(v, opt) {
                let ok = true;
                if ($("#node-config-input-clientid").length) {
                    // Currently editing the node
                    let needClientId = !$("#node-config-input-cleansession").is(":checked")
                    if (needClientId) {
                        ok = (v||"").length > 0;
                    }
                } else {
                    let needClientId = !(this.cleansession===undefined || this.cleansession)
                    if (needClientId) {
                        ok = (v||"").length > 0;
                    }
                }
                if (!ok) {
                    return RED._("node-red:mqtt.errors.invalid-client-id");
                }
                return true;
            }},
            autoConnect: {value: true},
            usetls: {value: false},
            verifyservercert: { value: false},
            compatmode: { value: false},
            protocolVersion: { value: 4},
            keepalive: {
                value:60,
                label: RED._("node-red:mqtt.label.keepalive"),
                validate:RED.validators.number(false)},
            cleansession: {value: true},
            autoUnsubscribe: {value: true},
            birthTopic: {value:"", validate:validateMQTTPublishTopic},
            birthQos: {value:"0"},
            birthRetain: {value:"false"},
            birthPayload: {value:""},
            birthMsg: { value: {}},
            closeTopic: {value:"", validate:validateMQTTPublishTopic},
            closeQos: {value:"0"},
            closeRetain: {value:"false"},
            closePayload: {value:""},
            closeMsg: { value: {}},
            willTopic: {value:"", validate:validateMQTTPublishTopic},
            willQos: {value:"0"},
            willRetain: {value:"false"},
            willPayload: {value:""},
            willMsg: { value: {}},
            userProps: { value: ""},
            sessionExpiry: {value:0}
        },
        credentials: {
            user: {type:"text"},
            password: {type: "password"}
        },
        label: function() {
            if (this.name) {
                return this.name;
            }
            var b = this.broker;
            if (!b) { b = "undefined"; }
            var lab = "";
            lab = (this.clientid?this.clientid+"@":"")+b;
            if (b.indexOf("://") === -1){
                if (!this.port){ lab = lab + ":1883"; }
                else { lab = lab + ":" + this.port; }
            }
            return lab;
        },
        oneditprepare: function () {
            var tabs = RED.tabs.create({
                id: "node-config-mqtt-broker-tabs",
                onchange: function(tab) {
                    $("#node-config-mqtt-broker-tabs-content").children().hide();
                    $("#" + tab.id).show();
                }
            });
            tabs.addTab({
                id: "mqtt-broker-tab-connection",
                label: this._("mqtt.tabs-label.connection")
            });
            tabs.addTab({
                id: "mqtt-broker-tab-security",
                label: this._("mqtt.tabs-label.security")
            });

            tabs.addTab({
                id: "mqtt-broker-tab-messages",
                label: this._("mqtt.tabs-label.messages")
            });

            function setUpSection(sectionId, v5Opts, isExpanded) {
                var birthMessageSection = $("#mqtt-broker-section-"+sectionId);
                var paletteHeader = birthMessageSection.find('.red-ui-palette-header');
                var twistie = paletteHeader.find('i');
                var sectionContent = birthMessageSection.find('.section-content');

                function toggleSection(expanded) {
                    twistie.toggleClass('expanded', expanded);
                    sectionContent.toggle(expanded);
                }
                paletteHeader.on("click", function(e) {
                    e.preventDefault();
                    var isExpanded = twistie.hasClass('expanded');
                    toggleSection(!isExpanded);
                });
                toggleSection(isExpanded);
                $("#node-config-input-"+sectionId+"-contentType").val(v5Opts?v5Opts.contentType:"").typedInput({
                    default: getDefaultContentType(v5Opts?v5Opts.contentType:""),
                    types: contentTypeOpts,
                });

                $("#node-config-input-"+sectionId+"-props").val(v5Opts?v5Opts.userProps:"").typedInput({
                    default:  !(v5Opts?v5Opts.userProps:null)? 'none':'json',
                    types: [typedInputNoneOpt, 'json'],
                });
                $("#node-config-input-"+sectionId+"-respTopic").val(v5Opts?v5Opts.respTopic:"").typedInput({
                    default:  !(v5Opts?v5Opts.respTopic:null)? 'none':'str',
                    types: [typedInputNoneOpt, 'str'],
                });
                $("#node-config-input-"+sectionId+"-correl").val(v5Opts?v5Opts.correl:"").typedInput({
                    default:  !(v5Opts?v5Opts.correl:null)? 'none':'str',
                    types: [typedInputNoneOpt, 'str'],
                });
                $("#node-config-input-"+sectionId+"-expiry").val(v5Opts?v5Opts.expiry:"").typedInput({
                    default:  !(v5Opts?v5Opts.expiry:null)? 'none':'num',
                    types: [typedInputNoneOpt, 'num'],
                });
            }

            // show first section if none are set so the user gets the idea
            var showBirthSection = this.birthTopic !== ""
                || this.willTopic === ""
                && this.birthTopic === ""
                && this.closeTopic == "";
            setUpSection('birth', this.birthMsg, showBirthSection);
            setUpSection('close', this.closeMsg, this.closeTopic !== "");
            setUpSection('will', this.willMsg, this.willTopic !== "");

            if (this.willMsg) {
                $("#node-config-input-will-delay").val(this.willMsg.delay);
            }

            setTimeout(function() { tabs.resize(); },0);
            if (typeof this.cleansession === 'undefined') {
                this.cleansession = true;
                $("#node-config-input-cleansession").prop("checked",true);
            }
            if (typeof this.autoUnsubscribe === 'undefined') {
                this.autoUnsubscribe = true;
                $("#node-config-input-autoUnsubscribe").prop("checked",true);
            }
            if (typeof this.usetls === 'undefined') {
                this.usetls = false;
                $("#node-config-input-usetls").prop("checked",false);
            }
            if (typeof this.autoConnect === 'undefined') {
                this.autoConnect = true;
                $("#node-config-input-autoConnect").prop("checked",true);
            }
            if (this.compatmode === 'true' || this.compatmode === true) {
                delete this.compatmode;
                this.protocolVersion = 4;
            }
            if (typeof this.protocolVersion === 'undefined') {
                this.protocolVersion = 4;
            }
            $("#node-config-input-cleansession").on("change", function() {
                const useCleanSession = $("#node-config-input-cleansession").is(':checked');
                if(useCleanSession) {
                    $("div.form-row.mqtt-persistence").hide();
                } else {
                    $("div.form-row.mqtt-persistence").show();
                }
            });
            $("#node-config-input-protocolVersion").on("change", function() {
                var v5 = $("#node-config-input-protocolVersion").val() == "5";
                if(v5) {
                    $("#node-config-input-cleansession-label").text(RED._("node-red:mqtt.label.cleanstart"))
                    $("div.form-row.mqtt5").show();
                } else {
                    $("#node-config-input-cleansession-label").text(RED._("node-red:mqtt.label.cleansession"))
                    $("div.form-row.mqtt5").hide();
                }
            });
            $("#node-config-input-protocolVersion").val(this.protocolVersion);
            $("#node-config-input-userProps").typedInput({
                default:  !this.userProps ? 'none':'json',
                types: [typedInputNoneOpt, 'json']
            });
            $("#node-config-input-userProps").typedInput('value',this.userProps);
            if (typeof this.keepalive === 'undefined') {
                this.keepalive = 15;
                $("#node-config-input-keepalive").val(this.keepalive);
            }
            if (typeof this.birthQos === 'undefined') {
                this.birthQos = "0";
                $("#node-config-input-birthQos").val("0");
            }
            if (typeof this.closeQos === 'undefined') {
                this.willQos = "0";
                $("#node-config-input-willQos").val("0");
            }
            if (typeof this.willQos === 'undefined') {
                this.willQos = "0";
                $("#node-config-input-willQos").val("0");
            }


            function updateTLSOptions() {
                if ($("#node-config-input-usetls").is(':checked')) {
                    $("#node-config-row-tls").show();
                } else {
                    $("#node-config-row-tls").hide();
                }
            }
            updateTLSOptions();
            $("#node-config-input-usetls").on("click",function() {
                updateTLSOptions();
            });
            var node = this;
            function updateClientId() {
                if ($("#node-config-input-cleansession").is(":checked")) {
                    $("#node-config-input-clientid").attr("placeholder",node._("mqtt.placeholder.clientid"));
                } else {
                    $("#node-config-input-clientid").attr("placeholder",node._("mqtt.placeholder.clientid-nonclean"));
                }
                $("#node-config-input-clientid").trigger("change");
            }
            setTimeout(updateClientId,0);
            $("#node-config-input-cleansession").on("click",function() {
                updateClientId();
            });

            function updatePortEntry(){
                var disabled = $("#node-config-input-port").prop("disabled");
                if ($("#node-config-input-broker").val().indexOf("://") === -1){
                    if (disabled){
                        $("#node-config-input-port").prop("disabled", false);
                    }
                }
                else {
                    if (!disabled){
                        $("#node-config-input-port").prop("disabled", true);
                    }
                }
            }
            $("#node-config-input-broker").on("change", function() {
                updatePortEntry();
            });
            $("#node-config-input-broker").on( "keyup", function() {
                updatePortEntry();
            });
            setTimeout(updatePortEntry,50);
            setTimeout(function() {
                $("#node-config-input-protocolVersion").trigger("change");
            },50);

        },
        oneditsave: function() {
            if (!$("#node-config-input-usetls").is(':checked')) {
                $("#node-config-input-tls").val("");
            }

            var v5 = $("#node-config-input-protocolVersion").val() == "5";

            function saveV5Message(section) {
                var msg = {};
                if ($("#node-config-input-"+section+"Topic").val().trim().length > 0) {
                    var contentType = $("#node-config-input-"+section+"-contentType").val().trim();
                    if (contentType === '') {
                        contentType = $("#node-config-input-"+section+"-contentType").typedInput('type');
                        if (contentType === 'none' || contentType === 'other') {
                            contentType = "";
                        }
                    }
                    if (contentType) {
                        msg.contentType = contentType;
                    }
                    var props = $("#node-config-input-"+section+"-props").val().trim();
                    if (props) {
                        msg.userProps = props;
                    }
                    var resp = $("#node-config-input-"+section+"-respTopic").val().trim();
                    if (props) {
                        msg.respTopic = resp;
                    }
                    var correl = $("#node-config-input-"+section+"-correl").val().trim();
                    if (correl) {
                        msg.correl = correl;
                    }
                    var expiry = $("#node-config-input-"+section+"-expiry").val().trim();
                    if (expiry) {
                        msg.expiry = expiry;
                    }
                }
                return msg;
            }

            if (v5) {
                this.userProps = "";
                const userPropsType = $("#node-config-input-userProps").typedInput("type");
                if(userPropsType == "json") {
                    const userProps = $("#node-config-input-userProps").val();
                    if (userProps && typeof userProps === "string") {
                        this.userProps = userProps.trim();
                    }
                }
                this.birthMsg = saveV5Message("birth");
                this.closeMsg = saveV5Message("close");
                this.willMsg = saveV5Message("will");
                var willDelay = $("#node-config-input-will-delay").val();
                if (willDelay) {
                    this.willMsg.delay = willDelay;
                }
            } else {
                this.willMsg = {};
                this.birthMsg = {};
                this.closeMsg = {};
            }

        }
    });

    RED.nodes.registerType('mqtt in',{
        category: 'network',
        defaults: {
            name: {value:""},
            topic: {
                value:"",
                validate: function(v, opt) {
                    var isDynamic = this.inputs === 1;
                    var topicTypeSelect = $("#node-input-topicType");
                    if (topicTypeSelect.length) {
                        isDynamic = topicTypeSelect.val()==='dynamic'
                    }
                    if (isDynamic || ((!!v) && RED.validators.regex(/^(#$|(\+|[^+#]*)(\/(\+|[^+#]*))*(\/(\+|#|[^+#]*))?$)/)(v))) {
                        return true;
                    }
                    return RED._("node-red:mqtt.errors.invalid-topic");
                }
            },
            qos: {value: "2"},
            datatype: {value:"auto-detect",required:true},
            broker: {type:"mqtt-broker", required:true, label:RED._("node-red:mqtt.label.broker")},
            // subscriptionIdentifier: {value:0},
            nl: {value:false},
            rap: {value:true},
            rh: {value:0},
            inputs: {value:0},
        },
        color:"#d8bfd8",
        inputs:0,
        outputs:1,
        icon: "bridge.svg",
        label: function() {
            var label = "mqtt";
            if(this.topicType !== "dynamic" && this.topic) {
                label = this.topic;
            }
            return this.name || label;
        },
        labelStyle: function() {
            return this.name?"node_label_italic":"";
        },
        oneditprepare: function() {
            const node = this;
            const isV5Broker = function() {
                var confNode = RED.nodes.node($("#node-input-broker").val());
                return confNode && confNode.protocolVersion === "5";
            }
            const isDynamic = function() {
                return $('#node-input-topicType').val() === "dynamic";
            }
            const updateVisibility = function() {
                var v5 = isV5Broker();
                var dynamic = isDynamic();
                $("div.form-row-mqtt5").toggleClass("form-row-mqtt5-active",!!v5);
                $("div.form-row.form-row-mqtt-static").toggleClass("form-row-mqtt-static-disabled", !!dynamic)
            }

            $("#node-input-datatype").on("change", function() {
                if($(this).val() === "auto") {
                    $(".form-row.form-row-mqtt-datatype-tip").show();
                } else {
                    $(".form-row.form-row-mqtt-datatype-tip").hide();
                }
            })
            $("#node-input-datatype").trigger("change");

            $("#node-input-broker").on("change",function(d){
                updateVisibility();
            });

            $('#node-input-topicType').on("change", function () {
                $("#node-input-inputs").val(isDynamic() ? 1 : 0);
                updateVisibility();
            });

            if (this.inputs === 1) {
                $('#node-input-topicType').val('dynamic')
            } else {
                $('#node-input-topicType').val('topic')
            }
            $('#node-input-topicType').trigger("change");

            if (this.qos === undefined) {
                $("#node-input-qos").val("2");
            }
            if (this.datatype === undefined) {
                $("#node-input-datatype").val("auto-detect");
            }
        },
        oneditsave: function() {
            if ($('#node-input-topicType').val() === "dynamic") {
                $('#node-input-topic').val("");
            }
        }
    });

    RED.nodes.registerType('mqtt out',{
        category: 'network',
        defaults: {
            name: {value:""},
            topic: {value:"", validate:validateMQTTPublishTopic},
            qos: {value:""},
            retain: {value:""},
            respTopic: {value:""},
            contentType: {value:""},
            userProps: {value:''},
            correl: {value:''},
            expiry: {value:''},
            broker: {type:"mqtt-broker", required:true,
                     label:RED._("node-red:mqtt.label.broker") }
        },
        color:"#d8bfd8",
        inputs:1,
        outputs:0,
        icon: "bridge.svg",
        align: "right",
        label: function() {
            return this.name||this.topic||"mqtt";
        },
        oneditprepare: function() {
            var that = this;

            function showHideDynamicFields() {
                var confNode = RED.nodes.node($("#node-input-broker").val());
                var v5 = confNode && confNode.protocolVersion == "5";
                if(v5) {
                    $("div.form-row.mqtt5").show();
                    var t = $("#node-input-respTopic").typedInput("type");
                    if (t == 'none') {
                        $("#node-input-correl").parent().hide();
                    } else {
                        $("#node-input-correl").parent().show();
                    }
                } else {
                    $("div.form-row.mqtt5").hide();
                }
            }

            $("#node-input-broker").on("change",function(d){
                showHideDynamicFields();
            });

            var respTopicTI = $("#node-input-respTopic").typedInput({
                default: !this.respTopic ? 'none':'str',
                types: [typedInputNoneOpt,  'str'],
            });

            var correlTI = $("#node-input-correl").typedInput({
                default: !this.correl ? 'none':'str',
                types: [typedInputNoneOpt,  'str']
            });
            //show / hide correlation data depending on respTopic
            respTopicTI.on("change", showHideDynamicFields);
            respTopicTI.triggerHandler("change");

            $("#node-input-userProps").typedInput({
                default:  !this.userProps ? 'none':'json',
                types: [typedInputNoneOpt, 'json'],
            });
            $("#node-input-expiry").typedInput({
                default: !this.expiry ? 'none':'num',
                types: [typedInputNoneOpt,  'num']
            });
            $("#node-input-contentType").typedInput({
                default: getDefaultContentType(this.contentType),
                types: contentTypeOpts
            })
        },
        oneditsave: function() {

            var contentType = $("#node-input-contentType").val().trim();
            if (contentType === '') {
                contentType = $("#node-input-contentType").typedInput('type');
                if (contentType === 'none' || contentType === 'other') {
                    contentType = "";
                }
            }
            $("#node-input-contentType").val(contentType)

        },
        labelStyle: function() {
            return this.name?"node_label_italic":"";
        }
    });
})();
</script>
